/*
* full-citys-api.js 省市区数据操作
* author:devin87@qq.com  
* update:2020/08/13 15:33
*/
(function (undefined) {
    var extend = Object.assign || Q.extend,
        dataAll = { countries: [] },
        map_country_by_id = {},
        map_data_by_code = {},
        map_data_by_name = {};

    var map_code_by_name = {
        '河北区': 'CN101031600',
        '河南县': 'CN101150304',
        '海南区': 'CN101080303',
        '海南州': 'CN101150402',
        '吉林市': 'CN101060201'
    };

    function init() {
        dataAll = { countries: [] };

        //将数组数据转为对象
        var format_data = function (data) {
            return { id: data[0], name: data[1], code: data[2] };
        };

        //获取子项列表
        var get_subs = function (key) {
            return dataAllCitys[key] || [];
        };

        (dataAllCitys.countries || [[0, '中国']]).forEach(function (data) {
            var data_country = format_data(data),
                key_provs = data_country.id,
                list_prov = [],
                list_all_city = [],
                map_prov_by_id = {},
                map_prov_by_name = {},
                map_city_by_name = {};

            data_country.type = 1;
            data_country.ctid = data_country.id;

            //provs
            get_subs(key_provs).forEach(function (data2) {
                var data_prov = format_data(data2),
                    key_citys = data_country.id + '_' + data_prov.id,
                    list_city = [],
                    map_city_by_id = {};

                data_prov.type = 2;
                data_prov.ctid = data_country.id;
                data_prov.pid = data_prov.id;

                //citys
                get_subs(key_citys).forEach(function (data3) {
                    var data_city = format_data(data3),
                        key_areas = data_country.id + '_' + data_prov.id + '_' + data_city.id,
                        list_area = [],
                        map_area_by_id = {};

                    data_city.type = 3;
                    data_city.ctid = data_prov.ctid;
                    data_city.pid = data_prov.id;
                    data_city.cid = data_city.id;

                    //areas
                    get_subs(key_areas).forEach(function (data4) {
                        var data_area = format_data(data4);
                        data_area.type = 4;
                        data_area.ctid = data_city.ctid;
                        data_area.pid = data_city.pid;
                        data_area.cid = data_city.id;
                        data_area.aid = data_area.id;

                        list_area.push(data_area);
                        map_area_by_id[data_area.id] = map_data_by_name[data_area.name] = map_data_by_code[data_area.code] = data_area;
                    });

                    list_city.push(data_city);
                    map_city_by_name[data_city.name] = map_city_by_id[data_city.id] = map_data_by_name[data_city.name] = map_data_by_code[data_city.code] = data_city;

                    data_city.mapAreaId = map_area_by_id;

                    dataAll[key_areas] = list_area;
                });

                list_prov.push(data_prov);
                map_prov_by_name[data_prov.name] = map_prov_by_id[data_prov.id] = data_prov;

                data_prov.mapCityId = map_city_by_id;

                list_all_city = list_all_city.concat(list_city);
                dataAll[key_citys] = list_city;
            });

            map_city_by_name['襄樊'] = map_city_by_name['襄阳'];

            data_country.citys = list_all_city;
            data_country.mapProvId = map_prov_by_id;
            data_country.mapProvName = map_prov_by_name;
            data_country.mapCityName = map_city_by_name;

            map_country_by_id[data_country.id] = data_country;

            dataAll[key_provs] = list_prov;
            dataAll.countries.push(data_country);
        });
    }

    init();

    /**
     * 格式化省份名称 eg:湖北省 => 湖北
     * @param {string} prov 
     */
    function formatProv(prov) {
        if (prov.length <= 2) return prov;
        return prov.replace(/[省市]$|国家及地区$/g, '');
    }

    /**
     * 格式化城市名称 eg:武汉市 => 武汉
     * @param {string} city 
     */
    function formatCity(city) {
        if (city.length <= 2) return city;
        return city.replace(/国家及地区$|特别行政区$|[州市]$|地区$/g, '');
    }

    /**
     * 获取国家列表 eg: [{id:0,name:'中国'}]
     */
    function getCountries() {
        return dataAll.countries;
    }

    /**
     * 获取子项列表
     * @param {string} key eg: 0|0_0|0_0_0
     */
    function getSubs(key) {
        return dataAll[key] || [];
    }

    /**
     * 根据国家id获取省份列表 eg: [{id:0,name:'北京',ctid:0}]
     * @param {string} ctid 国家id,默认为0
     */
    function getProvs(ctid) {
        return getSubs(ctid || '0');
    }

    /**
     * 根据国家id、省份id获取城市列表 eg: [{id:0,name:'海淀',ctid:0,pid:0}]
     * @param {string} pid 省份id,不能为空
     * @param {string} ctid 国家id,默认为0
     */
    function getCitys(pid, ctid) {
        return getSubs((ctid || '0') + '_' + pid);
    }

    /**
     * 根据国家id、省份id、城市id获取城区列表 eg: [{id:0,name:'蔡甸',ctid:0,pid:19,cid:0}]
     * @param {string} pid 省份id,不能为空
     * @param {string} cid 城市id,不能为空
     * @param {string} ctid 国家id,默认为0
     */
    function getAreas(pid, cid, ctid) {
        return getSubs((ctid || '0') + '_' + pid + '_' + cid);
    }

    /**
     * 获取国家对象 eg: {id:0,name:'中国'}
     * @param {string} ctid 国家id,默认为0
     */
    function getCountry(ctid) {
        return map_country_by_id[ctid || '0'];
    }

    /**
     * 获取省份对象 eg: {id:0,name:'北京',ctid:0}
     * @param {string} pid 省份id,不能为空
     * @param {string} ctid 国家id,默认为0
     */
    function getProv(pid, ctid) {
        var data_country = getCountry(ctid);
        return data_country ? data_country.mapProvId[pid] : undefined;
    }

    /**
     * 获取城市省份对象 eg: {id:0,name:'北京',ctid:0}
     * @param {string} pid 省份id,不能为空
     * @param {string} cid 城市id,不能为空
     * @param {string} ctid 国家id,默认为0
     */
    function getCity(pid, cid, ctid) {
        var data_prov = getProv(pid, ctid);
        return data_prov ? data_prov.mapCityId[cid] : undefined;
    }

    /**
     * 获取城区对象 eg: {id:0,name:'蔡甸',ctid:0,pid:19,cid:0}
     * @param {string} pid 省份id,不能为空
     * @param {string} cid 城市id,不能为空
     * @param {string} aid 城区id,不能为空
     * @param {string} ctid 国家id,默认为0
     */
    function getArea(pid, cid, aid, ctid) {
        var data_city = getCity(pid, cid, ctid);
        return data_city ? data_city.mapAreaId[aid] : undefined;
    }

    /**
     * 获取对象 eg: {id:0,name:'蔡甸',ctid:0,pid:19,cid:0}
     * @param {string} pid 省份id,为空则获取国家对象
     * @param {string} cid 城市id,为空则获取省份对象
     * @param {string} aid 城区id,为空则获取城市对象
     * @param {string} ctid 国家id,默认为0
     */
    function getAuto(pid, cid, aid, ctid) {
        if (aid != undefined) return getArea(pid, cid, aid, ctid);
        if (cid != undefined) return getCity(pid, cid, ctid);
        if (pid != undefined) return getProv(pid, cid, ctid);
        return getCountry(ctid);
    }

    /**
     * 格式化输出 eg: {type,code,ctid,pid,cid,aid,country,prov,city,area}
     * @param {object} data 省份、城市或地区对象
     */
    function formatData(data) {
        if (!data) return;

        var result = {};

        if (data.type) result.type = data.type;
        if (data.code) result.code = data.code;

        if (data.ctid != undefined) result.ctid = data.ctid;
        if (data.pid != undefined) result.pid = data.pid;
        if (data.cid != undefined) result.cid = data.cid;
        if (data.aid != undefined) result.aid = data.aid;

        result.country = (getCountry(result.ctid) || {}).name;
        if (result.pid != undefined) result.prov = (getProv(result.pid, result.ctid) || {}).name;
        if (result.cid != undefined) result.city = (getCity(result.pid, result.cid, result.ctid) || {}).name;
        if (result.aid != undefined) result.area = (getArea(result.pid, result.cid, result.aid, result.ctid) || {}).name;

        return result;
    }

    /**
     * 根据城市、地区代码或名称获取对象
     * @param {string} name 城市、地区代码或名称 eg: CN101010100|武汉
     * @param {boolean} is_format 是否格式化结果, 默认为true {pid,cid,id,name} => {type,code,ctid,pid,cid,aid,country,prov,city,area}
     */
    function getCityOrArea(name, is_format) {
        if (!name) return;

        var data = map_data_by_code[map_code_by_name[name] || name] || map_data_by_name[name];
        return data && is_format !== false ? formatData(data) : data;
    }

    /**
     * 根据城市、地区名称获取代码
     * @param {string} name 城市、地区名称 eg: 北京 => CN101010100
     */
    function getCode(name) {
        if (!name) return;

        var data = map_data_by_code[map_code_by_name[name] || name] || map_data_by_name[name];
        return data ? data.code : undefined;
    }

    /**
     * 根据省份名称查找省份对象
     * @param {string} prov 省份名称
     * @param {boolean} is_full_match 为true则不在省份列表中查找,直接返回结果
     * @param {string} ctid 国家id,默认为0
     */
    function findProv(prov, is_full_match, ctid) {
        if (!prov) return;

        var data_country = getCountry(ctid);
        if (!data_country) return;

        prov = formatProv(prov);

        var data_prov = data_country.mapProvName[prov];
        if (data_prov || is_full_match) return data_prov;

        var provs = getProvs(ctid);
        for (var i = 0, len = provs.length; i < len; i++) {
            data_prov = provs[i];
            if (prov.indexOf(data_prov.name) != -1) return data_prov;
        }
    }

    /**
     * 根据城市名称查找城市对象
     * @param {string} city 城市名称或代码
     * @param {Array.<object>} citys 城市对象列表 [{id,code,name}]
     */
    function findCityInList(city, citys) {
        for (var i = 0, len = citys.length; i < len; i++) {
            var data = citys[i];
            if (city.indexOf(data.name) != -1) return data;
        }
    }

    /**
     * 根据城市名称查找城市对象
     * @param {string} city 城市名称或代码
     * @param {Array.<object>|undefined} citys 城市列表,为空则查找所有城市
     * @param {boolean} is_full_match 为true则不在城市列表中查找,直接返回结果
     * @param {string} ctid 国家id,默认为0
     */
    function findCity(city, citys, is_full_match, ctid) {
        if (!city) return;

        city = formatCity(city).replace('襄樊', '襄阳').replace('思茅', '普洱');

        var data_city = map_data_by_code[city];
        if (data_city) return formatData(data_city);

        //若指定了城市列表，则优先在指定的城市列表中查找
        if (citys) return findCityInList(city, citys);

        data_city = getCityOrArea(city);

        var data_country = getCountry(ctid);
        if (!data_country) return data_city;

        if (!data_city) data_city = data_country.mapCityName[city];

        if (data_city || is_full_match) return data_city;

        return findCityInList(city, data_country.citys);
    }

    /**
     * 查找省市数据 => {type,code,ctid,pid,cid,country,prov,city}
     * @param {string} prov 省份
     * @param {string} city 城市
     * @param {string} ctid 国家id,默认为0
     */
    function findData(prov, city, ctid) {
        var data_prov, data_city, citys;

        if (prov) {
            data_prov = findProv(prov, false, ctid);
            if (data_prov) citys = getCitys(data_prov.id, ctid);
        }

        return formatData(findCity(city, citys) || data_prov);
    }

    /**
     * 查找省市对象 => {type,code,ctid,pid,cid,aid,country,prov,city,area}
     * @param {string} addr 省市地址 eg:湖北武汉 联通|湖北省武汉市|湖北武汉|湖北|武汉|武汉武汉
     * @param {boolean} is_full_match 是否完整匹配 eg: 海南州  => 青海省海南州
     * @param {string} ctid 国家id,默认为0
     */
    function find(addr, is_full_match, ctid) {
        var gs = (addr + '').split(' '),
            geo = gs[0] || '';

        if (!geo) return {};

        geo = geo + '';

        var result = getCityOrArea(geo);
        if (result) return result;

        var i = geo.indexOf('省');
        if (i > 0) return findData(geo.slice(0, i), geo.slice(i + 1), ctid);

        var data_prov = findProv(geo, is_full_match, ctid),
            data_city = findCity(geo, data_prov ? getCitys(data_prov.id, data_prov.ctid) : undefined, is_full_match, ctid);

        return formatData(data_city || data_prov);
    }

    var DC = {
        getSubs: getSubs,
        getCountries: getCountries,
        getProvs: getProvs,
        getCitys: getCitys,
        getAreas: getAreas,

        getCountry: getCountry,
        getProv: getProv,
        getCity: getCity,
        getArea: getArea,
        getAuto: getAuto,

        getCityOrArea: getCityOrArea,
        getCode: getCode,

        formatProv: formatProv,
        formatCity: formatCity,
        formatData: formatData,

        findProv: findProv,
        findCity: findCity,
        findData: findData,
        find: find
    };

    if (typeof module === 'object' && typeof module.exports === 'object') module.exports = DC;

    if (typeof window !== 'undefined') {
        window.DC2 = DC;
        if (!window.DC) window.DC = DC;
    }
})();